
from decimal import Decimal
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval, Bool

__all__ = ['Sale', 'SaleLine']
__metaclass__ = PoolMeta

class Sale:
    __name__ = 'pcw.sale'

    total_descuento_jubilado = fields.Numeric('Jubilados', digits=(16, 4),
        states={
            'readonly': Eval('state')  != 'draft',
            })
    total_anulaciones = fields.Numeric('Anulaciones',
        digits=(16, 4),
        states={
            'readonly': Eval('state')  != 'draft',
            })
    cantidad_tickets = fields.Integer('Tickets',
        states={
            'readonly': Eval('state')  != 'draft',
            })

    z_number = fields.Integer('Z No',
        states={
            'readonly': Eval('state')  != 'draft',
            })

    @classmethod
    def __setup__(cls):
        super(Sale, cls).__setup__()
        cls._error_messages.update({
                'oris_date': "Error al verificar la fecha del movimiento. '%s'",
                })

    @staticmethod
    def default_total_descuento_jubilado():
        return Decimal(0.00)

    @staticmethod
    def default_total_anulaciones():
        return Decimal(0.00)

    @staticmethod
    def default_cantidad_tickets():
        return 1

    @classmethod
    def process(cls, orders):
        pool = Pool()
        Config = pool.get('oris.configuration')
        config = Config(1)
        for order in orders:
            date_res = config.verify_oris_date(order.date)
            if not date_res[0]:
                cls.raise_user_error('oris_date', error_args=(date_res[1],))

        super(Sale, cls).process(orders)

    def create_move(self, line):
        if line.quantity == 0 or line.product.type == 'service':
            return None

        Move = Pool().get('pcw.stock.move')

        mv = Move()
        mv.date = self.date
        mv.type = 'out'
        mv.reference = self.name
        mv.product = line.product
        mv.quantity = line.quantity
        mv.uom = line.unit
        mv.unit_price = line.product.get_average_cost(line.unit) # ORIS change
        mv.company = self.company
        mv.currency = self.company.currency
        mv.order = self
        mv.save()
        if mv.id:
            line.move = mv.id
            line.save()
        return mv

    @classmethod
    def write(cls, sales, values):
        super(Sale, cls).write(sales, values)
        for sale in sales:
            sale.expand_subproducts()

    def expand_subproducts(self):
        obj_sale_line = Pool().get('pcw.sale.line')
        valores = {}

        lines = obj_sale_line.search([('sale','=',self.id), ('description','like','>%')])  
        #obj_sale_line.delete(lines) # Delete all subproducts
        if lines:
            return

        for line in self.sale_lines:
            total_cost_sublines = Decimal(0.0)

            if not line.product.subproducts or line.product.type != 'service':
                total_cost_sublines = line.product.get_average_cost(line.unit) * Decimal(line.quantity)

            for subline in line.product.subproducts:
                cost, valores = self.get_cost_line(subline, valores, line.quantity)
                total_cost_sublines = total_cost_sublines + cost 
               
            if total_cost_sublines > 0.0:
                if line.quantity > 0:
                    line.average_cost = Decimal('%.4f' % (total_cost_sublines / Decimal(line.quantity)))
                else:
                    line.average_cost = Decimal('%.4f' % total_cost_sublines)
                line.save() 

        if not valores:
            return

        for pr, det in valores.items():
            ln = obj_sale_line()
            ln.sale = self
            ln.product = det['product']
            ln.description = det['name']
            ln.unit_price = 0
            ln.unit = det['product_uom']
            ln.quantity = Decimal('%.4f' % det['qty'])
            ln.average_cost = Decimal('%.4f' % det['avg_cost']) 
            ln.save()

    def get_cost_line(self, subline, valores, parent_quantity):
        obj_uom = Pool().get('product.uom')

        total_cost_sublines = Decimal(0.0)

        if subline.product.subproducts: # Recursive
            for line in subline.product.subproducts:
                cost, valores = self.get_cost_line(line, valores, parent_quantity * obj_uom.compute_qty(subline.uom, subline.quantity, subline.product.default_uom))
                total_cost_sublines = total_cost_sublines + cost

        if subline.product.type == 'service':
            return [total_cost_sublines, valores]           

        subline_quantity = subline.quantity

        if subline.uom.id != subline.product.default_uom.id:
            subline_quantity = obj_uom.compute_qty(subline.uom, subline.quantity, subline.product.default_uom)

        quantity = subline_quantity * parent_quantity

        subline_avg_cost = subline.product.get_average_cost()
        total_cost_sublines = total_cost_sublines + (subline_avg_cost * Decimal(quantity))

        if not valores.get(subline.product.id, False):
            v = {
                'id':  subline.product.id,
                'name':  '%s%s' % ('> ', subline.product.name),
                'product':  subline.product,
                'qty':  quantity,
                'product_uom': subline.product.default_uom,
                'avg_cost': subline_avg_cost,
                }

            valores[subline.product.id] = v
        else:
            v = valores.get(subline.product.id, False) 
            v['qty'] = v['qty'] + quantity

        return [total_cost_sublines, valores]


class SaleLine:
    __name__ = 'pcw.sale.line'

    product = fields.Many2One('product.product', 'Product',
        states={
            'readonly': ~Eval('_parent_sale'),
            }, 
        on_change=['product', 'quantity', 'unit_price'], required=True)
    quantity = fields.Float('Qty',
        digits=(16, 4),
        states={
            'required': Bool(Eval('product')),
            'readonly': ~Eval('_parent_sale', {}),
            })
    average_cost = fields.Numeric('Average Cost', digits=(16, 4))

    @staticmethod
    def default_average_cost():
        return Decimal(0.00)


